#!/usr/bin/env python
# -*-coding:utf-8 -*-

__all__ = ['Dispatcher', 'getNearestIdleRobotController', 'dispatch']

import logging
from task import Task
from robot_controller import RobotController

class Dispatcher(object):
    def __init__(self, timer, map, router):
        """
        创建一个任务分发器。
        :param map: 地图。
        """
        self.initLogger()
        self._timer = timer
        self._map = map
        self._router = router
        
    def initLogger(self):
        self._logger = logging.getLogger('MyTCS.Dispatcher')
    
    def _assign(self, ctask, robot_controller):
        """
        将任务ctask指派给robots_controller控制的机器人执行。
        :param ctask: 复合任务（CompositeTask对象）。
        :param robots_manager: 机器人控制器（RobotController对象）。
        """
        ctask.assignTo(robot_controller)
        robot_controller.assign(ctask)
        next_task = ctask.getNextUncompletedTask()
        last_task = ctask.getLastUncompletedTask()
        self._logger.debug('Time={0:.2f} dispatcher assign task ({1},{2}) to robot {3}'.format( \
                           self._timer.getTime(), next_task.getSrc(), last_task.getDst(), robot_controller.getControlledRobotID()))
    
    def getNearestIdleRobotController(self, robot_controllers, waypoint):
        """
        获取到waypoint最近的机器人对应的controller。
        :param robot_controllers: 所有机器人的控制器的列表。
        :param waypoint: 找最近距离的终点（起点为各机器人的当前位置）。
        :return: c, min_cost，c为控制器，min_cost为该控制器控制的机器人到waypoint的距离。
        """
        if waypoint is None:
            return None
        min_cost = float('inf')
        c = None # a robot controller controls an IDLE robot
        for controller in robot_controllers:
            cwaypoint = controller.getCurrentWaypoint()
            if controller.getState() == RobotController.STATE_IDLE:
                cost = self._router.getShortestPathLength(cwaypoint, waypoint)
                if cost < min_cost:
                    min_cost = cost
                    c = controller
        return c, min_cost
                                
    def dispatch(self, ctask_queue, robots_manager):
        """
        将任务队列ctask_queue中的任务分发给robots_manager管理的机器人。
        :param ctask_queue: 复合任务队列（CompositeTaskQueue对象）。
        :param robots_manager: 机器人管理器（RobotsManager对象）。
        :return: 任务分发的结果。用一个元组的数组表示，比如[(ctask1, robot_controller1), (ctask2, robot_controller2)]
                 表示将ctask1分发给robot_controller1管理的机器人，ctask2分发给robot_controller2管理的机器人。
        """
        sorted_task_queue = list(ctask_queue)
        assign_list = []
        for ctask in sorted_task_queue:
            if not ctask.isAssigned():
                task = ctask.getNextUncompletedTask()
                src = task.getSrc()
                dst = task.getDst()
                #print 'trying to assign task from {0} to {1}'.format(task.getSrc(), task.getDst())
                robot_controllers = robots_manager.getRobotControllers()
                
                if src is not None:
                    c, min_cost = self.getNearestIdleRobotController(robot_controllers, src)
                    if c is not None:
                        # FixMe: default due time is 60 seconds.
                        if min_cost > 0.05:
                            # we need this robot to go to src, no matter where it is
                            t = Task(self._timer.getTime()+60, c.getCurrentWaypoint(), src)
                            ctask.addLeft(t)
                        self._assign(ctask, c)
                        assigned = True
                        assign_list.append((ctask, c))
                else:
                    c, min_cost = self.getNearestIdleRobotController(robot_controllers, dst)
                    if c is not None:
                        task.setSrc(c.getCurrentWaypoint())
                        self._assign(ctask, c)
                        assign_list.append((ctask, c))

        return assign_list
